
/*
 * file:   neiku/json.h
 * desc:   json tools for C++
 * author: hobby
 * date:   2015/05/30 22:49:00
 *
 * version: v1  -- json encoder
 *              基于C++的重载、宏技术，简单实现C++对象自动转成json字符串
 *              简单支持int32/64,uint32/64,std::string,std::vector
 *          v2  -- json encoder
 *              支持std::map，生成json对象；std::vector生成json数组
 *              新增json_encode(obj)宏，方便使用dump数据
 *          v3  -- json encoder
 *              引入jsoncpp第三方库，用于支持json字符串转义输出、后续
 *              json decoder实现基础
 *              TODO: 后续使用std::string来代替std::stringstream
 *          v4  将jsoncpp库放到3rd下面
 *          v5  -- json encoder
 *              支持json格式化(添加换行、缩进)，提高可读性
 *          v6  -- json encoder
 *              支持bool类型
 *          v7  -- json encoder
 *              区分单行json和格式化json生成工具，不要撸在一起
 *          v8  -- json decoder
 *              基于jsoncpp、重载、宏技术，简单实现json字符串自动转成C++对象
 *　　　　　　　支持对象(嵌套)、bool/int32/64,uint32/64,std::string
 *          v8  -- json decoder
 *              支持std::vector<T>，对应json的任意类型数组
 *          v9  -- json decoder
 *              支持double/float
 * usage:
 *       #include "neiku/json.h"
 *
 * compile: $(neiku_config --include --libs json)
 *
 * vim:ts=4;sw=4;expandtab
 */

#ifndef __NK_JSON_H__
#define __NK_JSON_H__ 1

#include <inttypes.h>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>

#include "jsoncpp/jsoncpp.h"
#include "neiku/serialize.h"

#define DUMP_OBJ(obj)       ((neiku::CJsonEncoder() << obj).str().c_str())
#define DUMP_JSON(obj)       ((neiku::CJsonEncoder() << obj).str().c_str())
#define json_encode(obj)       ((neiku::CJsonEncoder() << obj).str().c_str())
#define json_encode_ml(obj)    ((neiku::CJsonEncoderMl() << obj).str().c_str())
#define json_decode(body, obj) neiku::do_json_decode(body, obj)

namespace neiku
{

// JsonEncoder -- 支持C++对象自动生成JSON对象（字符串）
class CJsonEncoder
{
    public:
        CJsonEncoder(): m_bIsFirstKey(false)
        {};

        // 返回json
        std::string str()
        {
            return m_ssJson.str();
        }

        // json encode
        template <class T>
        CJsonEncoder& operator << (const T& o)
        {
            return *this & o;
        }

	public:
        CJsonEncoder& operator & (Key& key)
        {
            if (m_bIsFirstKey)
            {
                m_bIsFirstKey = false;
                m_ssJson << "\"" << key.c_str()<< "\":";
            }
            else
            {
                m_ssJson << ",\"" << key.c_str() << "\":";
            }
            return *this;
        }

        CJsonEncoder& operator & (bool b)
        {
            if (b == true)
            {
                m_ssJson << "true";
            }
            else
            {
                m_ssJson << "false";
            }
            return *this;
        }

        CJsonEncoder& operator & (int32_t i32)
        {
            m_ssJson << i32;
            return *this;
        }

        CJsonEncoder& operator & (int64_t i64)
        {
            m_ssJson << i64;
            return *this;
        }

        CJsonEncoder& operator & (uint32_t u32)
        {
            m_ssJson << u32;
            return *this;
        }

        CJsonEncoder& operator & (uint64_t u64)
        {
            m_ssJson << u64;
            return *this;
        }

        // 字符串两边由对引号包住
        CJsonEncoder& operator & (std::string& str)
        {
             m_ssJson << Json::valueToQuotedString(str.c_str());
            return *this;
        }

        // vector 视为 json 数组
        template <class T>
        CJsonEncoder& operator & (std::vector<T>& vector)
        {
            m_ssJson << "[";
            if (!vector.empty())
            {
                size_t index = 0;
                *this & vector[index];
                for (++index; index < vector.size(); ++index)
                {
                    m_ssJson << ",";
                    *this & vector[index];
                }
            }
            m_ssJson << "]";
            return *this;
        }

        // set 视为 json 数组
        template <class T>
        CJsonEncoder& operator & (std::set<T>& vector)
        {
            m_ssJson << "[";
            if (!vector.empty())
            {
                typename std::set<T>::iterator it = vector.begin();
                *this & *it;
                for (++it; it != vector.end(); ++it)
                {
                    m_ssJson << ",";
                    *this & *it;
                }
            }
            m_ssJson << "]";
            return *this;
        }

        // map 视为 json 对象
        template <class KEY, class VALUE>
        CJsonEncoder& operator & (std::map<KEY, VALUE>& map)
        {
            m_ssJson << "{";
            if (!map.empty())
            {
                typename std::map<KEY, VALUE>::iterator it = map.begin();
                std::stringstream ss;
                ss << it->first;
                m_ssJson << Json::valueToQuotedString(ss.str().c_str()) << ":";
                *this & it->second;
                for (++it; it != map.end(); ++it)
                {
                    // std::stringstream::str("") 才是真正的清空方法
                    ss.str("");
                    ss << it->first;
                    m_ssJson << "," << Json::valueToQuotedString(ss.str().c_str()) << ":";
                    *this & it->second;
                }
            }
            m_ssJson << "}";
            return *this;
        }

        // 自定义对象 视为 json 对象
        template <class T>
        CJsonEncoder& operator & (T& o)
        {
            bool b = m_bIsFirstKey;
            m_bIsFirstKey = true;
            m_ssJson << "{";
            o.serialize(*this);
            m_ssJson << "}";
            m_bIsFirstKey = b;
            return *this;
        }
        template <class T>
        CJsonEncoder& operator & (const T& o)
        {
            // 兼容const obj
            return *this & const_cast<T&>(o);
        }

    private:
        bool m_bIsFirstKey;
        std::stringstream m_ssJson;
};

// JsonEncoderMl -- 支持C++对象自动生成格式化JSON对象（自动填充换行、缩进）
class CJsonEncoderMl
{
    public:
        CJsonEncoderMl(): m_bIsFirstKey(false)
                        , m_iIndentNum(0)
        {};

        // 返回json
        std::string str()
        {
            return m_ssJson.str();
        }

        // json encode
        template <class T>
        CJsonEncoderMl& operator << (const T& o)
        {
            return *this & o;
        }

    public:
        CJsonEncoderMl& operator & (Key& key)
        {
            if (m_bIsFirstKey)
            {
                m_bIsFirstKey = false;
                m_ssJson << "\n" << Indent() << "\"" << key.c_str() << "\": ";
            }
            else
            {
                m_ssJson << "," << "\n" << Indent() << "\"" << key.c_str() << "\": ";
            }
            return *this;
        }

        CJsonEncoderMl& operator & (bool b)
        {
            if (b == true)
            {
                m_ssJson << "true";
            }
            else
            {
                m_ssJson << "false";
            }
            return *this;
        }

        CJsonEncoderMl& operator & (int32_t i32)
        {
            m_ssJson << i32;
            return *this;
        }

        CJsonEncoderMl& operator & (int64_t i64)
        {
            m_ssJson << i64;
            return *this;
        }

        CJsonEncoderMl& operator & (uint32_t u32)
        {
            m_ssJson << u32;
            return *this;
        }

        CJsonEncoderMl& operator & (uint64_t u64)
        {
            m_ssJson << u64;
            return *this;
        }

        // 字符串两边由对引号包住
        CJsonEncoderMl& operator & (std::string& str)
        {
             m_ssJson << Json::valueToQuotedString(str.c_str());
            return *this;
        }

        // vector 视为 json 数组
        template <class T>
        CJsonEncoderMl& operator & (std::vector<T>& vector)
        {
            m_ssJson << "[";
            if (!vector.empty())
            {
                int i  = m_iIndentNum;
                m_iIndentNum += 1;
                m_ssJson << "\n" << Indent();
                size_t index = 0;
                *this & vector[index];
                for (++index; index < vector.size(); ++index)
                {
                    m_ssJson << "," << "\n" << Indent();
                    *this & vector[index];
                }
                m_iIndentNum -= 1;
                m_ssJson << "\n" << Indent();
                m_iIndentNum = i;
            }
            m_ssJson << "]";
            return *this;
        }

        // set 视为 json 数组
        template <class T>
        CJsonEncoderMl& operator & (std::set<T>& vector)
        {
            m_ssJson << "[";
            if (!vector.empty())
            {
                int i  = m_iIndentNum;
                m_iIndentNum += 1;
                m_ssJson << "\n" << Indent();
                typename std::set<T>::iterator it = vector.begin();
                *this & *it;
                for (++it; it != vector.end(); ++it)
                {
                    m_ssJson << "," << "\n" << Indent();
                    *this & *it;
                }
                m_iIndentNum -= 1;
                m_ssJson << "\n" << Indent();
                m_iIndentNum = i;
            }
            m_ssJson << "]";
            return *this;
        }

        // map 视为 json 对象
        template <class KEY, class VALUE>
        CJsonEncoderMl& operator & (std::map<KEY, VALUE>& map)
        {
            m_ssJson << "{";
            if (!map.empty())
            {
                int i  = m_iIndentNum;
                m_iIndentNum += 1;
                typename std::map<KEY, VALUE>::iterator it = map.begin();
                std::stringstream ss;
                ss << it->first;
                m_ssJson << "\n" << Indent() << Json::valueToQuotedString(ss.str().c_str()) << ": ";
                *this & it->second;
                for (++it; it != map.end(); ++it)
                {
                    // std::stringstream::str("") 才是真正的清空方法
                    ss.str("");
                    ss << it->first;
                    m_ssJson << "," << "\n" << Indent() << Json::valueToQuotedString(ss.str().c_str()) << ": ";
                    *this & it->second;
                }
                m_iIndentNum -= 1;
                m_ssJson << "\n" << Indent();
                m_iIndentNum  = i;
            }
            m_ssJson << "}";
            return *this;
        }

        // 自定义对象 视为 json 对象
        template <class T>
        CJsonEncoderMl& operator & (T& o)
        {
            bool b = m_bIsFirstKey;
            int i  = m_iIndentNum;
            m_bIsFirstKey = true;
            m_ssJson << "{";
            m_iIndentNum += 1;
            o.serialize(*this);
            m_iIndentNum -= 1;
            m_ssJson << "\n" << Indent() << "}";
            m_bIsFirstKey = b;
            m_iIndentNum  = i;
            return *this;
        }
        template <class T>
        CJsonEncoderMl& operator & (const T& o)
        {
            // 兼容const obj
            return *this & const_cast<T&>(o);
        }

    private:
        std::string Indent()
        {
            return std::string(4 * (m_iIndentNum), ' ');
        }

    private:
        bool m_bIsFirstKey;
        std::stringstream m_ssJson;
        int  m_iIndentNum;
};

// JsonDecoder -- 支持JSON字符串向C++对象反序列化
class CJsonDecoder
{
    public:
        CJsonDecoder(): m_pCurrJsonValue(NULL)
                      , m_szKeyName(NULL)
        {}

        int Parse(const std::string& sJson)
        {
            Json::Reader reader;
            if (!reader.parse(sJson.c_str(), m_oJsonValueRoot))
            {
                #ifdef _JSON_SERIALIZE_DEBUG_
                LOG_ERR("parse json fail, json:[%s]", sJson.c_str());
                #endif
                return -1;
            }
            if (!m_oJsonValueRoot.isObject() && !m_oJsonValueRoot.isArray())
            {
                #ifdef _JSON_SERIALIZE_DEBUG_
                LOG_ERR("invalid object/array, json:[%s]", sJson.c_str());
                #endif
                return -1;
            }
            m_pCurrJsonValue = &m_oJsonValueRoot;
            return 0;
        }

        // json decode
        template <class T>
        CJsonDecoder& operator >> (T& o)
        {
            return *this & o;
        }

    public:
        CJsonDecoder& operator & (Key& key)
        {
            m_szKeyName = key.c_str();
            return *this;
        }

#define GEN_OPERATOR(type, method, str2num) \
        CJsonDecoder& operator & (type& o) \
        { \
            if (m_szKeyName == NULL) \
            { \
                o = m_pCurrJsonValue->method(); \
            } \
            else if (m_pCurrJsonValue->isMember(m_szKeyName)) \
            { \
                const Json::Value& value = (*m_pCurrJsonValue)[m_szKeyName]; \
                if (value.isString()) \
                { \
                    std::string v = value.asString(); \
                    o = str2num(v.c_str(), NULL, 0); \
                } \
                else \
                {  \
                    o = value.method(); \
                } \
            } \
            return *this; \
        }
        GEN_OPERATOR(int32_t,     asInt, strtol);
        GEN_OPERATOR(int64_t,     asInt64, strtoll);
        GEN_OPERATOR(uint32_t,    asUInt, strtoul);
        GEN_OPERATOR(uint64_t,    asUInt64, strtoull);

        CJsonDecoder& operator & (double_t& o)
        {
            if (m_szKeyName == NULL)
            {
                o = m_pCurrJsonValue->asDouble();
            }
            else if (m_pCurrJsonValue->isMember(m_szKeyName))
            {
                const Json::Value& value = (*m_pCurrJsonValue)[m_szKeyName];
                o = value.asDouble();
            }
            return *this;
        }

        CJsonDecoder& operator & (float_t& o)
        {
            if (m_szKeyName == NULL)
            {
                o = m_pCurrJsonValue->asFloat();
            }
            else if (m_pCurrJsonValue->isMember(m_szKeyName))
            {
                const Json::Value& value = (*m_pCurrJsonValue)[m_szKeyName];
                o = value.asFloat();
            }
            return *this;
        }

        CJsonDecoder& operator & (bool& o)
        {
            if (m_szKeyName == NULL)
            {
                o = m_pCurrJsonValue->asBool();
            }
            else if (m_pCurrJsonValue->isMember(m_szKeyName))
            {
                const Json::Value& value = (*m_pCurrJsonValue)[m_szKeyName];
                o = value.asBool();
            }
            return *this;
        }

        CJsonDecoder& operator & (std::string& o)
        {
            if (m_szKeyName == NULL)
            {
                o = m_pCurrJsonValue->asString();
            }
            else if (m_pCurrJsonValue->isMember(m_szKeyName))
            {
                const Json::Value& value = (*m_pCurrJsonValue)[m_szKeyName];
                o = value.asString();
            }
            return *this;
        }

        template <class T>
        CJsonDecoder& operator & (std::vector<T>& v)
        {
            Json::Value *pValue = NULL;
            if (m_szKeyName == NULL)
            {
                pValue = m_pCurrJsonValue;
            }
            else
            {
                if (!m_pCurrJsonValue->isMember(m_szKeyName))
                {
                    return *this;
                }
                pValue = &(*m_pCurrJsonValue)[m_szKeyName];
            }

            if (!pValue->isArray())
            {
                return *this;
            }

            Json::Value *pJsonValue = m_pCurrJsonValue;
            const char *szKeyName = m_szKeyName;
            for (Json::ArrayIndex i = 0; i < pValue->size(); ++i)
            {
                m_szKeyName = NULL;
                m_pCurrJsonValue = &(*pValue)[i];

                T t;
                *this & t;
                v.push_back(t);
            }
            m_szKeyName = szKeyName;
            m_pCurrJsonValue = pJsonValue;

            return *this;
        }

        template <class T>
        CJsonDecoder& operator & (std::set<T>& v)
        {
            Json::Value *pValue = NULL;
            if (m_szKeyName == NULL)
            {
                pValue = m_pCurrJsonValue;
            }
            else
            {
                if (!m_pCurrJsonValue->isMember(m_szKeyName))
                {
                    return *this;
                }
                pValue = &(*m_pCurrJsonValue)[m_szKeyName];
            }

            if (!pValue->isArray())
            {
                return *this;
            }

            Json::Value *pJsonValue = m_pCurrJsonValue;
            const char *szKeyName = m_szKeyName;
            for (Json::ArrayIndex i = 0; i < pValue->size(); ++i)
            {
                m_szKeyName = NULL;
                m_pCurrJsonValue = &(*pValue)[i];

                T t;
                *this & t;
                v.insert(t);
            }
            m_szKeyName = szKeyName;
            m_pCurrJsonValue = pJsonValue;

            return *this;
        }

        // 解析到 map<std::string, std::string>
        CJsonDecoder& operator & (std::map<std::string, std::string>& v)
        {
            Json::Value *pValue = NULL;
            if (m_szKeyName == NULL)
            {
                pValue = m_pCurrJsonValue;
            }
            else
            {
                if (!m_pCurrJsonValue->isMember(m_szKeyName))
                {
                    return *this;
                }
                pValue = &(*m_pCurrJsonValue)[m_szKeyName];
            }

            if (!pValue->isObject())
            {
                return *this;
            }

            Json::Value *pJsonValue = m_pCurrJsonValue;
            const char *szKeyName = m_szKeyName;
            Json::Value::Members members = pValue->getMemberNames();
            for (Json::Value::Members::iterator it = members.begin(); it != members.end(); it++)
            {
                m_szKeyName = NULL;
                m_pCurrJsonValue = &(*pValue)[*it];

                std::string t;
                *this & t;
                v.insert(std::map<std::string, std::string>::value_type(*it, t));
            }
            m_szKeyName = szKeyName;
            m_pCurrJsonValue = pJsonValue;

            return *this;
        }

        template <class T>
        CJsonDecoder& operator & (T& o)
        {
            Json::Value* pJsonValue = m_pCurrJsonValue;
            if (m_szKeyName != NULL)
            {
                m_pCurrJsonValue = &(*pJsonValue)[m_szKeyName];
                o.serialize(*this);
            }
            else
            {
                o.serialize(*this);
            }
            m_pCurrJsonValue = pJsonValue;
            return *this;
        }

    private:
        Json::Value  m_oJsonValueRoot;
        Json::Value* m_pCurrJsonValue;
        const char*  m_szKeyName;
};

template<typename T>
int do_json_decode(const std::string& body, T& o)
{
    CJsonDecoder decoder;
    int ret = decoder.Parse(body);
    if (ret != 0)
    {
        return ret;
    }
    decoder >> o;
    return 0;
}
};

#endif
